package com.pureut.scheduling.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson2.JSON;
import com.ibm.icu.text.DateFormat;
import com.ibm.icu.text.SimpleDateFormat;
import com.pureut.common.core.exception.GlobalException;
import com.pureut.common.core.utils.DateUtils;
import com.pureut.common.core.utils.StringUtils;
import com.pureut.common.core.web.domain.AjaxResult;
import com.pureut.common.security.utils.DictUtils;
import com.pureut.common.security.utils.SecurityUtils;
import com.pureut.production.api.FeignProductionService;
import com.pureut.production.api.domain.PublicScheduling;
import com.pureut.scheduling.domain.*;
import com.pureut.scheduling.domain.dto.*;
import com.pureut.scheduling.domain.vo.*;
import com.pureut.scheduling.mapper.SchedulingCalendarMapper;
import com.pureut.scheduling.mapper.SchedulingHoursMapper;
import com.pureut.scheduling.mapper.SchedulingPlanMapper;
import com.pureut.scheduling.mapper.SchedulingProductionMapper;
import com.pureut.scheduling.service.ISchedulingHoursService;
import com.pureut.scheduling.service.ISchedulingProductionService;
import com.pureut.system.api.FeignService;
import com.pureut.system.api.OrderFeignService;
import com.pureut.system.api.StorageFegin;
import com.pureut.system.api.domain.SysDictData;
import com.pureut.system.api.vo.FeginProductionPickingVo;
import com.pureut.system.api.vo.ProductionPickingRelationVo;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.SQLException;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description 生产排程实现类
 * @Date 23-01-05
 * @Author hl
 **/
@Service
public class SchedulingProductionServiceImpl implements ISchedulingProductionService {

    @Resource
    private SchedulingProductionMapper schedulingProductionMapper;

    @Resource
    private OrderFeignService orderFeignService;

    @Resource
    private FeignService feignService;

    @Resource
    private SchedulingHoursMapper schedulingHoursMapper;

    @Resource
    private SchedulingCalendarMapper schedulingCalendarMapper;

    @Resource
    private SchedulingPlanMapper schedulingPlanMapper;

    @Resource
    private FeignProductionService feignProductionService;

    @Resource
    private ISchedulingHoursService schedulingHoursService;

    @Resource
    private StorageFegin storageFegin;

    private int count = 1;


    /**
     * 生产排程
     *
     * @param schedulingProductionVo
     * @return List<SchedulingProductionDto> 生产排程返回类
     */
    @Override
    public List<SchedulingProductionDto> selectProductionList(SchedulingProductionVo schedulingProductionVo) {
        List<SysDictData> netArray = DictUtils.getDictCache("scheduling_production_state");
        Map<String, String> netMap = netArray.stream().collect(Collectors.toMap(SysDictData::getDictValue, SysDictData::getDictLabel));
        return schedulingProductionMapper.selectProductionList(schedulingProductionVo);
    }

    /**
     * 手动(合并)下达
     *
     * @param schedulingExecution 接受类
     * @return List<SchedulingProductionDto> 生产排程返回类
     */
    @Override
    public int insertSchedulingManual(SchedulingExecutionOn schedulingExecution) {
        //获取线边编码
        long lineId = schedulingExecution.getLineId();
        schedulingExecution.setExecutionSender(SecurityUtils.getUsername());
        schedulingExecution.setLineCode(schedulingCalendarMapper.selectCalendarLineCode(lineId));
        List<SchedulingMerge> list = schedulingExecution.getList();
        if (list != null) {
            SchedulingMerge merge = list.get(0);
            schedulingExecution.setMaterialCode(merge.getMaterialCode());
            schedulingExecution.setMaterialName(merge.getMaterialName());
            schedulingExecution.setPlanNote(merge.getPlanNote());
            schedulingExecution.setRemark(merge.getRemark());
            String custName = "";
            String custCode = "";
            for (SchedulingMerge me :
                    list) {
                custCode += me.getPlanCustomerCode() + ",";
                custName += me.getPlanCustomerName() + ",";
            }
            String[] code1 = schedulingExecution.getProductionCode().split(",");
            String[] code2 = code1[0].split("-");
            String cStr = "PC-" + code2[1];
            schedulingExecution.setExecutionDoc(cStr + "-" + docGenerate(cStr));
            String planCode = "";
            for (String str :
                    code1) {
                String[] str2 = str.split("-");
                planCode += "SJ-" + str2[1] + ",";
            }
            schedulingExecution.setPlanCode(planCode.substring(0, planCode.length() - 1));
            schedulingExecution.setPlanCustomerName(custName.substring(0, custName.length() - 1));
            schedulingExecution.setPlanCustomerCode(custCode.substring(0, custCode.length() - 1));
        } else {
            String[] code = schedulingExecution.getProductionCode().split("-");
            String srt = "PC-" + code[1];
            //获取计划单号
            String productionCode = schedulingExecution.getProductionCode();
            SchedulingProductionDto viewByProductionCode = schedulingProductionMapper.getViewByProductionCode(productionCode);
            long planId = viewByProductionCode.getPlanId();
            SchedulingOrderDto schedulingOrderDto = schedulingPlanMapper.selectPlanOnById(planId);
//            schedulingExecution.setPlanCode("SJ-" + code[1]);
            schedulingExecution.setPlanCode(schedulingOrderDto.getPlanCode());
            schedulingExecution.setExecutionDoc(srt + "-" + docGenerate(srt));

        }
        //增加已排程重量
        String[] codeS = schedulingExecution.getProductionCode().split(",");
        if (codeS.length > 1) {
            String[] mergeWeightS = schedulingExecution.getCombinedWeight().split(",");
            for (int b = 0; b < codeS.length; b++) {
                schedulingProductionMapper.updateProductionWeightAdd(codeS[b], Double.parseDouble(mergeWeightS[b]));
                schedulingPlanMapper.updateStatus(codeS[b]);
            }
        } else {
            schedulingProductionMapper.updateProductionWeightAdd(schedulingExecution.getProductionCode(), Double.parseDouble(schedulingExecution.getSchedulingWeight()));
            schedulingPlanMapper.updateStatus(schedulingExecution.getProductionCode());
        }

        //生成生产领料单
        FeginProductionPickingVo feginProductionPickingVo = new FeginProductionPickingVo();
        feginProductionPickingVo.setProductionLine(schedulingExecution.getLineCode());//领用产线

        String moNumber = schedulingExecution.getExecutionDoc().replaceAll("PC", "SC");

        feginProductionPickingVo.setMoNumber(moNumber);
        List<ProductionPickingRelationVo> stockOutInfoDetails = new ArrayList<>();

        List<BomDetailDto> bomList = schedulingExecution.getBomList();

        //算出BOM领料总重量
        BigDecimal bigDecimal = new BigDecimal("0");

        if (bomList!=null) {

            for (BomDetailDto bomDetailDto : bomList) {
                ProductionPickingRelationVo stockOutInfoDetail = new ProductionPickingRelationVo();
                stockOutInfoDetail.setMaterialCode(bomDetailDto.getMaterialCode());
                stockOutInfoDetail.setPlannedWeight(bomDetailDto.getRequiredWeight());
                stockOutInfoDetails.add(stockOutInfoDetail);

                bigDecimal = bigDecimal.add(new BigDecimal(String.valueOf(bomDetailDto.getRequiredWeight())));
            }

            feginProductionPickingVo.setBomList(stockOutInfoDetails);
            storageFegin.add(feginProductionPickingVo);

            schedulingExecution.setBomWeight(String.valueOf(bigDecimal));
            schedulingExecution.setBomCode(schedulingExecution.getBomCode());
        }

        return schedulingProductionMapper.insertSchedulingManual(schedulingExecution);
    }


    public String docGenerate(String str) {
        String max = schedulingProductionMapper.maxSchedulingManual(str);
        int maxIn = Integer.parseInt(max) + 1;
        String qw = "";
        if (maxIn < 10) {
            qw = "0" + maxIn;
        } else {
            qw = String.valueOf(maxIn);
        }
        return qw;
    }


    /**
     * 查询排程下达信息
     *
     * @param executionId 下达后id
     * @return PublicScheduling 生产返回类
     */
    public PublicScheduling selectExecutionById(long executionId) {
        return schedulingProductionMapper.selectExecutionById(executionId);
    }

    /**
     * 排程单撤回
     *
     * @param executionId 排程接收id
     * @return 1 成功 0 失败
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteExecutionById(long executionId) throws Exception {
        SchedulingExecutionVo dto = new SchedulingExecutionVo();
        dto.setExecutionId(executionId);
        List<SchedulingExecutionDto> list = schedulingProductionMapper.selectSchedulingExecution(dto);
        SchedulingExecutionDto exe = list.get(0);
        int states = exe.getExecutionState();
        List<SysDictData> netArray = DictUtils.getDictCache("scheduling_execution_state");
        Map<String, String> netMap = netArray.stream().collect(Collectors.toMap(SysDictData::getDictValue, SysDictData::getDictLabel));
        String dict = netMap.get(String.valueOf(states));
        int ins = 0;
        String ypCode = exe.getProductionCode();
        String[] ypCodeS = ypCode.split(",");
        //长度大于1 代表是合并单据 分别撤回
        if (ypCodeS.length > 1) {
            String[] mergeWeight = exe.getCombinedWeight().split(",");
            String[] productionCodeS = exe.getProductionCode().split(",");
            for (int i = 0; i < productionCodeS.length; i++) {
                int ui = schedulingProductionMapper.updateProductionWeight(productionCodeS[i], Double.parseDouble(mergeWeight[i]));
                if (ui == 0) {
                    throw new SQLException("撤回失败");
                }
            }
        } else {
            //需要将重量返回排程单
            double we = exe.getSchedulingWeight();
            String productionCodeS = exe.getProductionCode();
            int ui = schedulingProductionMapper.updateProductionWeight(productionCodeS, we);
            if (ui == 0) {
                throw new SQLException("撤回失败");
            }
        }
        ins = schedulingProductionMapper.deleteExecutionById(executionId);
        if (ins == 0) {
            throw new SQLException("撤回失败");
        }
        //待生产 需要删除制令单数据
        if (states == 2) {
            String codeDoc = exe.getExecutionDoc().replace("PC", "SC");
            boolean flag = feignProductionService.remove(codeDoc);
            if (!flag) {
                throw new SQLException("撤回失败");
            }
        }
        return ins;
    }

    /**
     * 查询单个
     *
     * @param productionId 排程接收id
     * @return ProductionMaterialDto 排程AND物料AND订单信息结合返回类
     */
    @Override
    public ProductionMaterialDto selectProductionById(long productionId) {
        ProductionMaterialDto dto = schedulingProductionMapper.selectProductionById(productionId);
        //获取网型标准缓存字典数据
        List<SysDictData> netArray = DictUtils.getDictCache("sys_of_type");
        Map<String, String> netMap = netArray.stream().collect(Collectors.toMap(SysDictData::getDictValue, SysDictData::getDictLabel));
        dto.setMaterialNetDict(String.valueOf(netMap.get(dto.getMaterialNet())));
        //获取铺网类型标准缓存字典数据
        List<SysDictData> netTypeArray = DictUtils.getDictCache("sys_type_net");
        Map<String, String> netTypeMap = netTypeArray.stream().collect(Collectors.toMap(SysDictData::getDictValue, SysDictData::getDictLabel));
        dto.setMaterialNetTypeDict(String.valueOf(netTypeMap.get(dto.getMaterialNetType())));
        return dto;
    }

    /**
     * 计算预计开工时间AND分切数量AND母卷幅宽
     *
     * @param lineId 线别id
     * @return SchedulingExecution 下达返回类
     */
    @Override
    public SchedulingExecution getStartWork(long lineId, String materialCode, int widthCloth) throws ParseException, SQLException {
        SchedulingExecution exe = new SchedulingExecution();
        String time = schedulingProductionMapper.getStartWork(lineId);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        int hourTime = schedulingHoursMapper.selectHoursBirthTime(materialCode, lineId);
        if (hourTime == 0) {
            throw new SQLException("该线别产品未配置标准工时");
        }
        Date parse;
        if (StringUtils.isEmpty(time)) {
            time = DateUtils.getTime();
            parse = simpleDateFormat.parse(time);
        } else {
            //寻找该物料线别下的换产时间
            Calendar c = Calendar.getInstance();
            Date dateX = simpleDateFormat.parse(time);
            c.setTime(dateX);
            c.add(Calendar.MINUTE, hourTime);
            parse = c.getTime();
        }
        //需要查看时间在不在上班的工厂日历内 如果不在自动补充
        Long calId = schedulingCalendarMapper.selectCalendarLineOnById(lineId);
        if (ObjectUtil.isNull(calId) ) {
            throw new SQLException("该线别产品未配置工厂日历");
        }
        SchedulingCalendarVo schedulingCalendarVo = new SchedulingCalendarVo();
        schedulingCalendarVo.setCalendarId(calId);
        List<SchedulingCalendarDto> listDto = schedulingCalendarMapper.selectCalendarList(schedulingCalendarVo);
        SchedulingCalendarDto dto = listDto.get(0);
        //先判断节假日是否上班
        HolidayVo vo = schedulingCalendarMapper.selectCalendarSchedule(parse);
        if (vo == null) {
            //证明不是节假日or调休
            //判断是否是周末
            SimpleDateFormat sdf = new SimpleDateFormat("EEEE");
            String week = sdf.format(parse);
            //周六
            int saturday = dto.getCalendarSaturdayWork();
            //周天
            int weekend = dto.getCalendarWeekendWork();
            if ("星期六".equals(week)) {
                //判断周六是否上班
                if (saturday == 1) {//上班
                    //上班后 还需要判断时间在不在班次里
                    exe.setStartTime(rangeDate(parse, calId, hourTime, 1));
                } else {
                    //周六不上班 需要判断周日需不需要上班
                    if (weekend == 1) {//上班
                        exe.setStartTime(rangeDate(extraDays(parse, 1), calId, hourTime, 1));
                    } else {
                        //不上班 自动排到周一
                        exe.setStartTime(rangeDate(extraDays(parse, 2), calId, hourTime, 1));
                    }
                }
            } else if ("星期日".equals(week)) {
                //上班
                if (weekend == 1) {
                    exe.setStartTime(rangeDate(parse, calId, hourTime, 1));
                } else {
                    //加一天
                    exe.setStartTime(rangeDate(extraDays(parse, 1), calId, hourTime, 1));
                }
            } else {
                exe.setStartTime(rangeDate(parse, calId, hourTime, 1));
            }
        } else {
            //证明当天是节假日or调休
            if ("2".equals(vo.getStatus())) {
                //判断节假日是否上班
                int holiday = dto.getCalendarHolidayWork();//节假日上班
                if (holiday == 2) {
                    //节假日不上班 就需要找到节假日结束后第一天工作日
                    String max = schedulingCalendarMapper.maxCalendarScheduleMsg(vo.getMsg());
                    Date dateMax = simpleDateFormat.parse(max);
                    //加一天
                    exe.setStartTime(rangeDate(extraDays(parse, 1), calId, hourTime, 1));
                } else {
                    //加一天
                    exe.setStartTime(rangeDate(parse, calId, hourTime, 1));
                }
            } else if ("3".equals(vo.getStatus())) {
                //今天调休
                //加一天
                exe.setStartTime(rangeDate(parse, calId, hourTime, 1));
            }
        }
        AjaxResult shopResult = feignService.getModelingInfo(lineId);
        SysShopModeling shop = JSON.parseObject(JSON.toJSONString(shopResult.get("data")), SysShopModeling.class);
        //定幅宽
        int modelingWidth = shop.getModelingWidth();
        //最小切边
        int modelingMin = shop.getModelingMinTrimming();
        //最大切边
        //int modelingMax = shop.getModelingMaxTrimming();
        int fen = modelingWidth - modelingMin;
        fen = fen / widthCloth;
        //分切数量
        exe.setExecutionSlitting(fen);
        exe.setRollWidth(fen * widthCloth + modelingMin);
        return exe;
    }

    /**
     * 判断日期在不在范围内容 type(1 加换产时间 2 不加换产时间)
     */
    public long rangeDate(Date parse, long calId, int hourTime, int type) throws ParseException {
        //获取班次时间
        List<CalendarTeam> teamList = schedulingCalendarMapper.selectCalendarTeamList(calId);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        SimpleDateFormat formatS = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm");
        List<Integer> kaiList = new ArrayList<Integer>();
        //上班后 还需要判断时间在不在班次里
        String ban = dateFormat.format(parse);
        String[] ju = ban.split(":");
        //换算成分钟
        int kox = Integer.parseInt(ju[0]) * 60 + Integer.parseInt(ju[1]);
        boolean flag = false;
        //不在范围内 判断在不在休息范围内 查询休息时间
        List<CalendarRest> restList = schedulingCalendarMapper.selectCalendarRestList(calId);
        if (restList.size() > 0) {
            for (CalendarRest rest :
                    restList) {
                String xiuKai = rest.getRestStartTime();
                String[] xiuKaiS = xiuKai.split(":");
                String xiuJie = rest.getRestEndTime();
                String[] xiuJieS = xiuJie.split(":");
                //换算成分钟 (开始)
                int xiuK = Integer.parseInt(xiuKaiS[0]) * 60 + Integer.parseInt(xiuKaiS[1]);
                //换算成分钟 (结束)
                int xiuJ = Integer.parseInt(xiuJieS[0]) * 60 + Integer.parseInt(xiuJieS[1]);
                //跨天标识 1跨 2不跨
                int xiuKua = rest.getRestTranssky();
                if (xiuKua == 1) {
                    xiuJ += 24 * 60;
                }
                if (kox >= xiuK && kox <= xiuJ) {
                    //如果在休息时间里 找到对应班次 分钟+1
                    kox = xiuJ + 60;
                    flag = true;
                    break;
                }
            }
        }
        if (!flag) {
            for (CalendarTeam cal :
                    teamList) {
                //开始时间
                String kai = cal.getTeamStartTime();
                String[] kaiS = kai.split(":");
                //结束时间
                String jie = cal.getTeamEndTime();
                String[] jieS = jie.split(":");
                //换算成分钟 (开始)
                int stx = Integer.parseInt(kaiS[0]) * 60 + Integer.parseInt(kaiS[1]);
                //换算成分钟 (结束)
                int enx = Integer.parseInt(jieS[0]) * 60 + Integer.parseInt(jieS[1]);
                //跨天标识 1跨 2不跨
                int kua = cal.getTeamTranssky();
                if (kua == 1) {
                    //加上跨天时间
                    enx += 24 * 60;
                }
                //判断时间在不在范围内
                if (kox >= stx && kox <= enx) {
                    flag = true;
                    break;
                } else {
                    kaiList.add(stx);
                }
            }
        }
        //不在班次里也不在休息时间 证明时间存在空白时间 需要找出空白时间最近的下个班次
        if (!flag) {
            Collections.sort(kaiList);
            for (int yh :
                    kaiList) {
                if (kox < yh) {
                    kox = yh;
                }
            }
        }
        int hours = kox / 60;
        if (hours > 24) {
            hours -= 24;
            parse = extraDays(parse, 1);
        }
        int minutes = kox % 60;
        String zui = hours + ":" + String.valueOf(minutes);
        String jks = formatS.format(parse);
        //String mn = jks + " " + zui + ":" + "00";
        StringBuilder str = new StringBuilder();
        String mn = str.append(jks).append(" ").append(zui).append(":").append("00").toString();
        parse = simpleDateFormat.parse(mn);
        //开工时间
        if (type == 1) {
            Calendar c = Calendar.getInstance();
            c.setTime(parse);
            c.add(Calendar.MINUTE, hourTime);
            parse = c.getTime();
        }
        return parse.getTime();
    }


    /**
     * 排程确认
     *
     * @param executionId 确认接受类
     * @return 返回 1成功 2失败
     */
    @Transactional(rollbackFor = Exception.class)
    public int confirmSchedulingExecution(long executionId) throws Exception {
        int i = schedulingProductionMapper.confirmSchedulingExecution(executionId);
        int i1 = 0;
        if (i > 0) {
            //往生产模块传递数据
            PublicScheduling publicScheduling = new PublicScheduling();
            publicScheduling = selectExecutionById(executionId);
            i1 = feignProductionService.addOrderCutScheduling(publicScheduling);
            if (i1 == 0) {
                throw new SQLException("生成水刺制令单报错,请重试!");
            }
        }
        return i1;
    }

    /**
     * 查询生产排程(下达后)
     */
    @Override
    public List<SchedulingExecutionDto> selectSchedulingExecution(SchedulingExecutionVo schedulingExecutionVo) {
        return schedulingProductionMapper.selectSchedulingExecutionList(schedulingExecutionVo);
    }

    /**
     * 计算完工时间(冠军版)
     */
    public Date getFinishWork2(SchedulingExecutionMeterVo vo) throws ParseException {
        //预计开工时间
        String kai = vo.getExpStartTime();
        long lineId = vo.getLineId();
        SchedulingHoursDto dto = schedulingHoursMapper.selectHoursOnById(lineId, vo.getMaterialCode());
        //预计工时
        double standard = dto.getHoursStandard();
        List<SysDictData> netArray = DictUtils.getDictCache("scheduling_hours_formula");
        assert netArray != null;
        Map<String, String> netMap = netArray.stream().collect(Collectors.toMap(SysDictData::getDictValue, SysDictData::getDictLabel));
        String formula = netMap.get(String.valueOf(dto.getHoursTimeFormula()));
        //排产重量
        double schWeight = vo.getSchedulingWeight();
        double gramWeight = schedulingPlanMapper.selectGramWeightOnById(vo.getMaterialCode());
        //排程重量
        BigDecimal we1 = new BigDecimal(schWeight);
        //标准工时
        BigDecimal b4 = new BigDecimal(standard);
        BigDecimal b5 = new BigDecimal(360);
        BigDecimal b6x = new BigDecimal(60);
        //订单幅宽
        BigDecimal b1 = new BigDecimal(vo.getWidthCloth());
        b1 = BigDecimal.valueOf(1000);
        //分切数量
        BigDecimal b2 = new BigDecimal(vo.getExecutionSlitting());
        //预计工时
        double kl = 0.0;
        long hour = 0;
        if ("M/S".equals(formula)) {
            BigDecimal we2 = new BigDecimal(1000);
            BigDecimal we3 = we1.multiply(we2);
            //克重
            BigDecimal b3 = new BigDecimal(gramWeight);
            BigDecimal b6 = b1.multiply(b2).divide(b3, 2, RoundingMode.HALF_UP).multiply(we2).divide(b4, 2, RoundingMode.HALF_UP).divide(b5, 2, RoundingMode.HALF_UP);
            //最终预计工时
            kl = we3.divide(b6, 2, RoundingMode.HALF_UP).doubleValue();

        } else if ("KG/S".equals(formula)) {
            kl = we1.divide(b4, 2, RoundingMode.HALF_UP).divide(b5, 2, RoundingMode.HALF_UP).doubleValue();
        }
        //查找日历中的空白以及休息时间 (循环各班次的工作时间、减去休息时间 计算其中的空白时间)
        hour = (long) (kl * 60);
        //获取工厂日历的id
        long cal = schedulingCalendarMapper.selectCalendarLineOnById(lineId);
        //根据日历计算一天工作多长时间 poorMinutes
        long poorMinutes = schedulingCalendarMapper.numCalendarLine(cal);
        //day需要的天数 根据天数找周末和节假日是否上班 如果为0则今天就可以生产完
        int day = (int) (hour / poorMinutes);
        if (day > 0) {

        } else {
            //直接加上预计工时
            List<CalendarTeam> teamList = schedulingCalendarMapper.selectCalendarTeamList(cal);
            //算出开工时间在哪个班次里
            for (CalendarTeam calendarTeam :
                    teamList) {
                String startTime = calendarTeam.getTeamStartTime();
                String endTime = calendarTeam.getTeamStartTime();
                if (calendarTeam.getTeamTranssky() == 1) {
                    //代表跨天
                    String[] reamPoints = endTime.split(":");
                    int points1 = 24 + Integer.parseInt(reamPoints[0]);
                    endTime = points1 + reamPoints[1];
                }
                if (kai.compareTo(startTime) > 0 && endTime.compareTo(kai) > 0) {


                }
            }


        }


        List<CalendarTeam> teamList = schedulingCalendarMapper.selectCalendarTeamList(cal);
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //循环班次时间
        for (CalendarTeam calendarTeam :
                teamList) {
            //计算相差时间
            long startTime = sdf.parse(calendarTeam.getTeamStartTime()).getTime();
            long endTime = sdf.parse(calendarTeam.getTeamEndTime()).getTime();
            long diff = (endTime - startTime) / 1000 / 60;
            //计算这个班次的休息时间
            List<CalendarRest> restList = schedulingCalendarMapper.selectCalendarRestList(lineId);
            long restHour = 0;
            if (restList.size() > 0) {
                for (CalendarRest calendarRest :
                        restList) {
                    long restTime = sdf.parse(calendarRest.getRestStartTime()).getTime();
                    long restime = sdf.parse(calendarRest.getRestEndTime()).getTime();
                    long restDiff = (restime - restTime) / 1000 / 60;
                    restHour += restDiff;
                }
            }
            //班次时间减去他的休息时间
            diff -= restHour;
            if (diff >= hour) {
                //证明直接在这个班次结束 开工时间+预计工时 结束
                Date wanTime = timeProcess(sdf1.parse(kai), hour);
                //还需要判断这个时间在不在休息时间内 如果在 自动加到该班次的休息结束时间
                long shi = sdf.parse(sdf.format(wanTime)).getTime();
                for (CalendarRest calendarRest :
                        restList) {

                }

                return timeProcess(sdf1.parse(kai), hour);
            }
        }


        return new Date();
    }


    /**
     * 将传入的时间减去10分钟并返回
     *
     * @param date
     * @return
     */
    public Date timeProcess(Date date, long hour) {
        Calendar rightNow = Calendar.getInstance();
        rightNow.setTime(date);
        //rightNow.add(Calendar.MINUTE, -10); //减10分钟
        //rightNow.add(Calendar.HOUR,1);//加一个小时
        rightNow.add(Calendar.MINUTE, 10);
        //rightNow.add(Calendar.DAY_OF_MONTH,1);//加一天
        //rightNow.add(Calendar.MONTH,1);//加一个月
        Date dt1 = rightNow.getTime();
        return dt1;
    }


    /**
     * 根据排产重量and订单幅宽and分切expStartTime数量返回预计工时and完工时间
     */
    @Override
    public SchedulingExecutionMeter getFinishWork(SchedulingExecutionMeterVo vo) throws ParseException {
        SchedulingExecutionMeter meter = new SchedulingExecutionMeter();
        long lineId = vo.getLineId();
        SchedulingHoursDto dto = schedulingHoursMapper.selectHoursOnById(vo.getLineId(), vo.getMaterialCode());
        //预计工时
        double standard = dto.getHoursStandard();
        List<SysDictData> netArray = DictUtils.getDictCache("scheduling_hours_formula");
        assert netArray != null;
        Map<String, String> netMap = netArray.stream().collect(Collectors.toMap(SysDictData::getDictValue, SysDictData::getDictLabel));
        String formula = netMap.get(String.valueOf(dto.getHoursTimeFormula()));
        //排产重量
        double schWeight = vo.getSchedulingWeight();
        double gramWeight = schedulingPlanMapper.selectGramWeightOnById(vo.getMaterialCode());
        //排程重量
        BigDecimal we1 = new BigDecimal(schWeight);
        //标准工时
        BigDecimal b4 = new BigDecimal(standard);
        BigDecimal b5 = new BigDecimal(360);
        BigDecimal b6x = new BigDecimal(60);
        //订单幅宽
        BigDecimal b1 = new BigDecimal(vo.getWidthCloth());
        b1 = BigDecimal.valueOf(1000);
        //分切数量
        BigDecimal b2 = new BigDecimal(vo.getExecutionSlitting());
        double kl = 0.0;
        if ("M/S".equals(formula)) {
            BigDecimal we2 = new BigDecimal(1000);
            BigDecimal we3 = we1.multiply(we2);
            //克重
            BigDecimal b3 = new BigDecimal(gramWeight);
            BigDecimal b6 = b1.multiply(b2).divide(b3, 2, RoundingMode.HALF_UP).multiply(we2).divide(b4, 2, RoundingMode.HALF_UP).divide(b5, 2, RoundingMode.HALF_UP);
            //最终预计工时
            kl = we3.divide(b6, 2, RoundingMode.HALF_UP).doubleValue();

        } else if ("KG/S".equals(formula)) {
            kl = we1.divide(b4, 2, RoundingMode.HALF_UP).divide(b5, 2, RoundingMode.HALF_UP).doubleValue();
        }
        DecimalFormat df1 = new DecimalFormat("######0.00");
        meter.setExpWhen(Double.parseDouble(df1.format(kl)));
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        AjaxResult shopResult = feignService.getModelingInfo(vo.getLineId());
        SysShopModeling shop = JSON.parseObject(JSON.toJSONString(shopResult.get("data")), SysShopModeling.class);

        BigDecimal a1 = new BigDecimal(shop.getModelingMinTrimming()); //最小切边
        BigDecimal k2x = a1.multiply(we1).divide(b1, 2, RoundingMode.HALF_UP).multiply(b2).divide(b6x, 2, RoundingMode.HALF_UP);
        double k2 = k2x.setScale(2, RoundingMode.HALF_UP).doubleValue();
        DecimalFormat df = new DecimalFormat("######0.00");
        meter.setTrimmingWeight(Double.parseDouble(df.format(k2)));
        String sd = vo.getExpStartTime();
        long shi = sdf1.parse(sd).getTime();
        String lk = String.valueOf(kl);
        String[] lkS = lk.split("\\.");
        long l1;
        int ks4 = lkS.length;
        if (ks4 > 1) {
            l1 = Long.parseLong(lkS[0]) * 60 + Long.parseLong(lkS[1]);
        } else {
            l1 = (long) k2;
        }
        //算出预计完工时间 (该时间未包含休息时间以及周末and节假日)
        long wan = shi + l1 * 60 * 1000;
        //判断节假日和周末是否工作 如工作 则跳过
        SchedulingCalendar cal = schedulingCalendarMapper.selectCalendarLineWeekend(lineId);
        int saturday = cal.getCalendarSaturdayWork();
        int weekend = cal.getCalendarWeekendWork();
        int holiday = cal.getCalendarHolidayWork();
        if (saturday == 1 && weekend == 1 && holiday == 1) {
            //周末以及节假日都需要上班 故无需增加休息时间
            meter.setExpEndTime(wan);
        } else {
            //证明需要增加天数
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
            Date d1 = new Date(wan);
            Date d2 = new Date(shi);
            //long d3 = d1.getTime();//预计结束时间时间戳
            //long d4 = d2.getTime();//预计开始时间时间戳
            //先判断天数包不包含周末and节假日
            SimpleDateFormat sdf = new SimpleDateFormat("EEEE");
            //相差天数
            long day = DateUtils.getDatePoorDays(d1, d2);
            //用开始时间便利增加相差天数 如包含周末或节假日 预计完工时间+1天
//            if(holiday == 0){
            //证明节假日需要+1 判断相差天数里 包不包含节假日 如包含 天数+1
            //    }
            for (long i = 0; i < day; i++) {
                Date ti = extraDays(d2, 1);
                if (holiday == 2) {
                    int is = schedulingCalendarMapper.selectCalendarScheduleOnById(simpleDateFormat.format(ti));
                    if (is > 0) {
                        //完工时间加一天
                        d1 = extraDays(d1, 1);
                        continue;
                    }
                }
                String week = sdf.format(ti);
                if (saturday == 2) {
                    //代表周六不上班
                    if ("星期六".equals(week)) {
                        //完工时间加一天
                        d1 = extraDays(d1, 1);
                        continue;
                    }
                }
                if (weekend == 2) {
                    if ("星期日".equals(week)) {
                        //完工时间加一天
                        d1 = extraDays(d1, 1);
                        continue;
                    }
                }
            }
            meter.setExpEndTime(d1.getTime());
        }
        long calId = schedulingCalendarMapper.selectCalendarLineOnById(lineId);
        meter.setExpEndTime(rangeDate(sdf1.parse(sdf1.format(meter.getExpEndTime())), calId, 0, 2));
        return meter;
    }


    /**
     * T+N锁定
     */
    @Override
    public int insertSchedulingLock(SchedulingLockVo schedulingLockVo) {
        return schedulingProductionMapper.insertSchedulingLock(schedulingLockVo);
    }

    /**
     * 甘特图展示
     */
    @Override
    public List<GanttChartDto> selectGanttChart() throws ParseException {
        SchedulingExecutionVo vo = new SchedulingExecutionVo();
        List<SchedulingExecutionDto> list = schedulingProductionMapper.selectSchedulingExecutionList(vo);
        List<GanttChartDto> dtoList = new LinkedList<>();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat sdf = new SimpleDateFormat("EEEE");
        for (SchedulingExecutionDto scheduling :
                list) {
            GanttChartDto dtoX = new GanttChartDto();
            long exeId = scheduling.getExecutionId();
            String klS = "A" + exeId;
            dtoX.setId(klS);
            dtoX.setRender("split");
            dtoX.setLineName(scheduling.getLineName());
            dtoX.setText(scheduling.getLineName());
            dtoList.add(dtoX);
            Date startTime = scheduling.getExpStartTime();
            Date endTime = scheduling.getExpEndTime();
            long lineId = scheduling.getLineId();
            int check = schedulingCalendarMapper.countCalendarLineOnById(lineId);
            if (check == 0) {
                continue;
            }
            long calId = schedulingCalendarMapper.selectCalendarLineOnById(lineId);
            SchedulingCalendar cal = schedulingCalendarMapper.selectCalendarLineWeekend(scheduling.getLineId());
            int saturday = cal.getCalendarSaturdayWork();
            int sunday = cal.getCalendarWeekendWork();
            int holiday = cal.getCalendarHolidayWork();
            //查询开始时间和结束时间内含不含周末或节假日 获取相差天数
            int days = differentDaysByMillisecond(startTime, endTime);
            days += 1;
            //周六周日节假日都工作 真尼玛的良心工作
            List<String> hoList = schedulingCalendarMapper.selectScheduleCount(startTime, endTime, 2);
            List<String> hoList2 = schedulingCalendarMapper.selectScheduleCount(startTime, endTime, 3);
            for (int j = 0; j < days; j++) {
                if (j > 0) {
                    startTime = extraDays(startTime, 1);
                }
                String startStr = simpleDateFormat.format(startTime);
                //判断今天是周几
                String week = sdf.format(startTime);
                if (holiday == 2) {
                    //节假日不上班
                    if (hoList.contains(startStr)) {
                        continue;
                    }
                }
                switch (week) {
                    case "星期六":
                        if (saturday == 1) {
                            //调用
                            dtoList = ganttChartScheduling(dtoList, calId, startTime, klS, j, days, endTime);
                        } else if (hoList2.contains(startStr)) {
                            //判断是否是调休
                            //调用
                            dtoList = ganttChartScheduling(dtoList, calId, startTime, klS, j, days, endTime);
                        }
                        break;
                    case "星期日":
                        if (sunday == 1) {
                            //调用
                            dtoList = ganttChartScheduling(dtoList, calId, startTime, klS, j, days, endTime);
                        } else if (hoList2.contains(startStr)) { //判断是否是调休
                            //调用
                            dtoList = ganttChartScheduling(dtoList, calId, startTime, klS, j, days, endTime);
                        }
                        break;
                    default:
                        dtoList = ganttChartScheduling(dtoList, calId, startTime, klS, j, days, endTime);
                        break;
                }
            }
            //换产时间
            GanttChartDto dto2 = new GanttChartDto();
            int hourTime = schedulingHoursMapper.selectHoursBirthTime(scheduling.getMaterialCode(), lineId);
            Calendar c = Calendar.getInstance();
            c.setTime(scheduling.getExpStartTime());
            c.add(Calendar.MINUTE, -hourTime);
            dto2.setId("H" + exeId);
            dto2.setParent(klS);
            dto2.setText("换产时间");
            dto2.setColor("#539fe8");
            dto2.setStart_date(c.getTime());
            dto2.setEnd_date(scheduling.getExpStartTime());
            dtoList.add(dto2);
            count = 1;
        }
        count = 1;
        return dtoList;
    }

    /**
     * 开工时间and休息时间补充(封装调用)
     */
    public List<GanttChartDto> ganttChartScheduling(List<GanttChartDto> list, long calId, Date startTime, String klS, int j, int days, Date endTime) throws ParseException {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat simpleDateFormat2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        SimpleDateFormat simpleDateFormat3 = new SimpleDateFormat("HH:mm");
        String startStr = simpleDateFormat.format(startTime);
        String startStr2 = simpleDateFormat3.format(startTime);
        String endStr = simpleDateFormat3.format(endTime);
        List<CalendarTeam> teamList = schedulingCalendarMapper.selectCalendarTeamList(calId);//获取班次时间
        List<CalendarRest> restList = schedulingCalendarMapper.selectCalendarRestList(calId);
        if (count > 1) {
            startStr2 = "00:00";
        }
        for (int l = 0; l < teamList.size(); l++) {
            CalendarTeam calTeam = teamList.get(l);
            String teamEnd = calTeam.getTeamEndTime();
            String teamSt = calTeam.getTeamStartTime();
            if (startStr2.compareTo(teamEnd) > 0) {
                continue;
            }
            //计算生产时间
            GanttChartDto dto5 = new GanttChartDto();
            if (count == 1) {
                //植入开工时间
                dto5.setStart_date(startTime);
                count++;
            } else {
                //植入开工时间
                dto5.setStart_date(simpleDateFormat2.parse(startStr + " " + teamSt));
            }
            int across = calTeam.getTeamTranssky();
            //跨天
            if (across == 1) {
                Date acrossTime = extraDays(startTime, 1);
                //跨天生产日期
                startStr = simpleDateFormat.format(acrossTime);
            }
            if (j + 1 == days && teamEnd.compareTo(endStr) > 0) {
                //最后一次
                //植入结束时间
                dto5.setEnd_date(simpleDateFormat2.parse(startStr + " " + endStr + ":00"));
            } else {
                //植入结束时间
                dto5.setEnd_date(simpleDateFormat2.parse(startStr + " " + teamEnd));
            }
            if (dto5.getStart_date().compareTo(dto5.getEnd_date()) > 0) {
                continue;
            }
            dto5.setColor("#abf15e");
            dto5.setParent(klS);
            dto5.setId("T" + l + j + klS);
            list.add(dto5);
            for (int m = 0; m < restList.size(); m++) {
                CalendarRest rest = restList.get(m);
                if (teamSt.compareTo(rest.getRestEndTime()) > 0 || startStr2.compareTo(rest.getRestEndTime()) > 0) {
                    continue;
                } else if (j + 1 == days && rest.getRestStartTime().compareTo(endStr) > 0) {
                    continue;
                } else {
                    GanttChartDto dto6 = new GanttChartDto();
                    String hughTime = rest.getRestStartTime();
                    dto6.setStart_date(simpleDateFormat2.parse(startStr + " " + hughTime));
                    int tra = rest.getRestTranssky();
                    if (tra == 1) {
                        //跨天
                        Date acrossTime2 = extraDays(startTime, 1);
                        //跨天休息日期
                        String across2 = simpleDateFormat.format(acrossTime2);
                        dto6.setEnd_date(simpleDateFormat2.parse(across2 + " " + rest.getRestEndTime()));
                    } else {
                        dto6.setEnd_date(simpleDateFormat2.parse(startStr + " " + rest.getRestEndTime()));
                    }
                    dto6.setColor("#f1f1f1");
                    dto6.setParent(klS);
                    dto6.setId("X" + m + j + klS);
                    list.add(dto6);
                }
            }
        }
        return list;
    }


    /**
     * 甘特图拖拽
     */
    @Override
    public int ganttChartEdit(GanttChartVo ganttChartVo) {
        return schedulingProductionMapper.ganttChartEdit(ganttChartVo);
    }

    /**
     * 合并下达(展示)
     */
    @Override
    public List<ProductionMaterialDto> selectProductionCombined(String productionIdS) {
        String[] productionId = productionIdS.split(",");
        List<ProductionMaterialDto> list = new ArrayList<>();
        for (String pid :
                productionId) {
            long pidS = Long.parseLong(pid);
            list.add(selectProductionById(pidS));
        }

        for (ProductionMaterialDto productionMaterialDto : list) {

            String rollDiameter = productionMaterialDto.getRollDiameter();

            String thickness = productionMaterialDto.getThickness();

            String materialCode = productionMaterialDto.getMaterialCode();


            for (ProductionMaterialDto materialDto : list) {
                String rollDiameter1 = materialDto.getRollDiameter();

                String thickness1 = materialDto.getThickness();

                String materialCode1 = materialDto.getMaterialCode();

                if (!rollDiameter.equals(rollDiameter1)){
                    throw new GlobalException("只有同产品编码、同卷径、同厚度）的单据才可合并下达");
                }

                if (!thickness.equals(thickness1)){
                    throw new GlobalException("只有同产品编码、同卷径、同厚度）的单据才可合并下达");
                }

                if (!materialCode.equals(materialCode1)){
                    throw new GlobalException("只有同产品编码、同卷径、同厚度）的单据才可合并下达");
                }
            }

        }

        return list;
    }

    /**
     * 合并下达(保存)
     */
    @Override
    public int insertSchedulingCombinedThe(List<SchedulingExecutionOn> formList) {
        //排程id
        StringBuilder pcId = new StringBuilder();
        //排程编码
        StringBuilder pcCode = new StringBuilder();
        //排程合并重量
        StringBuilder pcWeight = new StringBuilder();
        //排程合并分切数量
        StringBuilder pcSlitting = new StringBuilder();
        for (SchedulingExecutionOn execution :
                formList) {
            pcId.append(execution.getProductionId()).append(",");
            pcCode.append(execution.getProductionCode()).append(",");
            pcWeight.append(execution.getSchedulingWeight()).append(",");
            pcSlitting.append(execution.getExecutionSlitting()).append(",");
        }
        String pcIdS = pcId.substring(0, pcId.length() - 1);
        String pcCodeS = pcId.substring(0, pcCode.length() - 1);
        String pcWeightS = pcId.substring(0, pcWeight.length() - 1);
        String pcSlittingS = pcId.substring(0, pcSlitting.length() - 1);
        SchedulingExecutionOn vo = new SchedulingExecutionOn();
        vo.setProductionId(pcIdS);
        vo.setProductionCode(pcCodeS);
        vo.setCombinedWeight(pcWeightS);
        vo.setExecutionSlitting(pcSlittingS);
        return schedulingProductionMapper.insertSchedulingManual(vo);
    }

    /**
     * 校验分切数量是否符合规则
     */
    @Override
    public int getCheckSlitting(int executionSlitting, int widthCloth) {
        return 0;
    }

    /**
     * 返回物料信息以及相应重量
     */
    @Override
    public List<MaterialRatioDto> getMaterialRatio(String materialCode, double schedulingWeight) {
        //根据物料解析出对应得BOM信息
        AjaxResult result = feignService.detailComposition(materialCode);
        List<MaterialBomDetailApi> bomDetailList = JSON.parseArray(JSON.toJSONString(result.get("data")), MaterialBomDetailApi.class);
        List<MaterialRatioDto> ratioList = new ArrayList<>();
        for (MaterialBomDetailApi bom :
                bomDetailList) {
            MaterialRatioDto ratio = new MaterialRatioDto();
            int proportion = bom.getBomDetailDosage();
            ratio.setNeedWeight(proportion * schedulingWeight / 100);
            ratio.setMaterialCode(bom.getMaterialCode());
            ratio.setMaterialName(bom.getMaterialName());
            ratio.setMaterialSpec(bom.getMaterialSpec());
            ratioList.add(ratio);
        }
        return ratioList;
    }

    /**
     * 回传修改时间开始时间和实际完工时间
     */
    @Override
    public int updateBackAdjust(BackAdjustVo backAdjustVo) {
        int i = schedulingProductionMapper.updateBackAdjust(backAdjustVo);
        return i;
    }

    /**
     * 回传产出重量
     */
    @Override
    public int updateBackWeight(BackWeight backWeight) {
        return schedulingProductionMapper.updateBackWeight(backWeight);
    }

    /**
     * 根据开工时间和预计工时算出完工时间
     */
    @Override
    public Date selectFinishTime(SchedulingTake schedulingTake) throws ParseException {
        long finishLong;
        long lineId = schedulingTake.getLineId();
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        long shi = schedulingTake.getExpStartTime();
        double ks4 = schedulingTake.getExpWhen();
        String lk = String.valueOf(ks4);
        String[] lkS = lk.split("\\.");
        long l1;
        int ks5 = lkS.length;
        if (ks5 > 1) {
            l1 = Long.parseLong(lkS[0]) * 60 + Long.parseLong(lkS[1]);
        } else {
            l1 = (long) ks4;
        }
        long wan = shi + l1 * 60 * 1000;
        //判断节假日和周末是否工作 如工作 则跳过
        SchedulingCalendar cal = schedulingCalendarMapper.selectCalendarLineWeekend(lineId);
        int saturday = cal.getCalendarSaturdayWork();
        int weekend = cal.getCalendarWeekendWork();
        int holiday = cal.getCalendarHolidayWork();
        if (saturday == 1 && weekend == 1 && holiday == 1) {
            //周末以及节假日都需要上班 故无需增加休息时间
            finishLong = wan;
        } else {
            //证明需要增加天数
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
            Date d1 = new Date(wan);
            Date d2 = new Date(shi);
            //long d3 = d1.getTime();//预计结束时间时间戳
            //long d4 = d2.getTime();//预计开始时间时间戳
            //先判断天数包不包含周末and节假日
            SimpleDateFormat sdf = new SimpleDateFormat("EEEE");
            //相差天数
            long day = DateUtils.getDatePoorDays(d1, d2);
            //用开始时间便利增加相差天数 如包含周末或节假日 预计完工时间+1天
//            if(holiday == 0){
            //证明节假日需要+1 判断相差天数里 包不包含节假日 如包含 天数+1
            //    }
            for (long i = 0; i < day; i++) {
                Date ti = extraDays(d2, 1);
                if (holiday == 2) {
                    int is = schedulingCalendarMapper.selectCalendarScheduleOnById(simpleDateFormat.format(ti));
                    if (is > 0) {
                        //完工时间加一天
                        d1 = extraDays(d1, 1);
                        continue;
                    }
                }
                String week = sdf.format(ti);
                if (saturday == 2) {
                    //代表周六不上班
                    if ("星期六".equals(week)) {
                        //完工时间加一天
                        d1 = extraDays(d1, 1);
                        continue;
                    }
                }
                if (weekend == 2) {
                    if ("星期日".equals(week)) {
                        //完工时间加一天
                        d1 = extraDays(d1, 1);
                        continue;
                    }
                }
            }
            finishLong = d1.getTime();
        }
        long calId = schedulingCalendarMapper.selectCalendarLineOnById(lineId);
        finishLong = (rangeDate(sdf1.parse(sdf1.format(finishLong)), calId, 0, 2));
        return sdf1.parse(sdf1.format(finishLong));
    }

    /**
     * 获取两个日期相差的天数
     */
    public int differentDaysByMillisecond(Date date1, Date date2) throws ParseException {
        DateFormat dft = new SimpleDateFormat("yyyy-MM-dd");
        //开始时间
        Date star = dft.parse(dft.format(date1));
        //结束时间
        Date endDay = dft.parse(dft.format(date2));
        Long starTime = star.getTime();
        Long endTime = endDay.getTime();
        //时间戳相差的毫秒数
        Long num = endTime - starTime;
        int day = (int) (num / 24 / 60 / 60 / 1000);
        //   System.out.println("相差天数为：" + num / 24 / 60 / 60 / 1000);//除以一天的毫秒数
        return day;
    }

    /**
     * 增加天数
     */
    public Date extraDays(Date parse, int day) {
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(parse);
        // 把日期往后增加一天,整数  往后推,负数往前移动
        calendar.add(Calendar.DATE, day);
        // 这个时间就是日期往后推一天的结果
        return calendar.getTime();
    }

    /**
     * 排程BOM物料列表
     * @param materialCode
     * @param schedulingWeight
     * @param bomId
     * @param lineId
     * @param trimmingWeight
     * @return
     */
    @Override
    public List<BomDetailDto> queryBom(String materialCode, double schedulingWeight, Long bomId, Long lineId, double trimmingWeight) {
        //BOM查询出来的物料列表
        AjaxResult halfData = feignService.listDetailInventory(bomId);
        List<MaterialBomHalfDetailDto> bomDetailList = JSON.parseArray(JSON.toJSONString(halfData.get("data")), MaterialBomHalfDetailDto.class);
        if (bomDetailList == null) {
            throw new GlobalException("没有查询到该物料下所属的bom明细物料数据");
        }
        List<BomDetailDto> bomDetailDtoList = new ArrayList<>();
        for (MaterialBomHalfDetailDto entity : bomDetailList) {
            BomDetailDto bomDetailDto = new BomDetailDto();
            bomDetailDto.setMaterialName(entity.getMaterialName());
            bomDetailDto.setMaterialCode(entity.getMaterialCode());
            bomDetailDto.setMaterialSpec(entity.getMaterialSpec());
            //所需重量 = (计划重量 * bom对应物料用量)/100 + 计划重量
            //所需重量 = 排产重量+产线损耗=排产重量/产成比
            BigDecimal planWeightBigDecimal = new BigDecimal(String.valueOf(schedulingWeight));
            //获取该线别下对应的标准工时
            SchedulingHoursDto data = schedulingHoursService.selectHoursOnById(lineId, materialCode);

            if (data.getLineYieldRatio() != null) {

                //产成比计算
                BigDecimal productionRatio = new BigDecimal(String.valueOf(data.getLineYieldRatio())).divide(new BigDecimal("100"));
                //排产重量 / 产成比
                BigDecimal sum = planWeightBigDecimal.divide(productionRatio,1);

                //切边重量
                BigDecimal bigDecimal = new BigDecimal(String.valueOf(trimmingWeight));

                //排产重量+产线损耗+切边
                BigDecimal add1 = bigDecimal.add(sum);
                //获取占比
                String bomProportion = entity.getBomProportion();

                BigDecimal divide = new BigDecimal(bomProportion).divide(new BigDecimal("100"));

                BigDecimal multiply = add1.multiply(divide);

                bomDetailDto.setRequiredWeight(Double.parseDouble(String.valueOf(multiply)));
            } else {
               throw new GlobalException("请先配置标准工时");
            }
            //库存重量
            Double stockWeight = storageFegin.getStockWeight(entity.getMaterialCode());

            //赋值库存量
            bomDetailDto.setInventoryWeight(stockWeight);

            Double requiredWeight = bomDetailDto.getRequiredWeight();
            // //如果所需重量大于库存重量
            // if (requiredWeight.compareTo(stockWeight) > 0) {
            //     BigDecimal subtract1 = new BigDecimal(String.valueOf(stockWeight)).multiply(new BigDecimal(100));
            //     BigDecimal divide1 = subtract1.divide(new BigDecimal(data.getLineYieldRatio()), RoundingMode.UP);
            //     throw new GlobalException("当前库存无法满足生产量，建议计划重量为" + divide1 + "kg");
            // }
            bomDetailDtoList.add(bomDetailDto);
        }
        return bomDetailDtoList;
    }
}